package com.codedancer.campus.manager.interceptor;


import cn.hutool.core.util.ObjectUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.codedancer.campus.common.anno.InterfacePermission;
import com.codedancer.campus.common.anno.PassToken;
import com.codedancer.campus.common.exception.BusinessException;
import com.codedancer.campus.mapper.AdminMapper;
import com.codedancer.campus.mapper.AdminRoleMapper;
import com.codedancer.campus.mapper.RoleMapper;
import com.codedancer.campus.po.Admin;
import com.codedancer.campus.po.AdminRole;
import com.codedancer.campus.po.Role;
import java.lang.reflect.Method;
import java.util.Arrays;
import javax.security.auth.message.AuthException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * ClassName AuthInterceptor Description 用户认证拦截器
 **/
@Component
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {


    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private RoleMapper roleMapper;

    /**
     * 登录验证
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
        Object handler)
        throws Exception {
        String token = request.getHeader("AUTH_TOKEN");
        if (ObjectUtil.isEmpty(token)) {
            token = request.getParameter("AUTH_TOKEN");
        }
        if (!(handler instanceof HandlerMethod)) {
            return HandlerInterceptor.super.preHandle(request, response, handler);
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        //检查是否有passtoken注释，有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return HandlerInterceptor.super.preHandle(request, response, handler);
            }
        } else {
            // 执行认证
            if (token == null) {
                log.error("登录token为空");
                throw new BusinessException("登录失效，请重新登录");
            }
            // 获取 token 中的  id
            String uuid;
            try {
                uuid = JWT.decode(token).getAudience().get(0);
            } catch (JWTDecodeException j) {
                log.error("uuid不存在，token：{}", token);
                throw new BusinessException("登录失效，请重新登录");
            }
            Admin admin = adminMapper.findById(uuid)
                .orElseThrow(() -> new BusinessException("用户不存在"));

            // 判断用户是否被禁用
            if (admin.getDisabled()) {
                throw new BusinessException("已禁用");
            }
            // 获取管理员角色
            AdminRole adminRole = adminRoleMapper.findByColumn("admin_uuid", admin.getUuid())
                .orElseThrow(() -> new BusinessException("管理员未绑定角色，请联系超级管理员"));
            Role role = roleMapper.findById(adminRole.getRoleUuid())
                .orElseThrow(() -> new BusinessException("管理员角色不存在"));
            // 校验是否可以调用接口
            if (method.isAnnotationPresent(InterfacePermission.class)) {
                InterfacePermission interfacePermission = method.getAnnotation(
                    InterfacePermission.class);
                String[] encodes = interfacePermission.encodes();
                if (!Arrays.asList(encodes).contains(role.getEncode())) {
                    throw new BusinessException("接口无权限");
                }
            }
            // 验证 token
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(admin.getPassword())).build();
            try {
                jwtVerifier.verify(token);
            } catch (JWTVerificationException e) {
                log.error("token校验失败，token：{}", token);
                throw new AuthException("登录失效，请重新登录");
            }
            return HandlerInterceptor.super.preHandle(request, response, handler);
        }
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }
}
